use super::IdReq;
use crate::{
    error::AppErr,
    store::device::{edit_device, login, query_devices, Device},
    web::codec::{
        cbor::{new_ok_cbor, Cbor, CborRet},
        device_session::{get_device_session, remove_session, save_session},
        user_session::UserSession,
        Void,
    },
};
use actix_web::{
    get, post,
    web::{self, Query, ServiceConfig},
};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct LoginReq {
    mac_addr: String,
}

#[post("/login")]
async fn on_login(req: Cbor<LoginReq>) -> CborRet<Device> {
    let device = login(&req.mac_addr).await?;
    save_session(device.id);
    new_ok_cbor(device)
}

#[get("/query")]
async fn on_query(_: UserSession) -> CborRet<Box<[Device]>> {
    let devices = query_devices().await?;
    new_ok_cbor(devices)
}

#[get("/poll_timestamp")]
async fn on_query_last_poll_timestamp(_: UserSession, req: Query<IdReq>) -> CborRet<u64> {
    let timestamp = get_device_session(req.id)?.last_poll_timestamp();
    new_ok_cbor(timestamp)
}

#[post("/edit")]
async fn on_edit(_: UserSession, device: Cbor<Device>) -> Result<Void, AppErr> {
    edit_device(&device).await?;
    remove_session(device.id);
    Ok(Void)
}

pub fn register(cfg: &mut ServiceConfig) {
    let scope = web::scope("/device")
        .service(on_login)
        .service(on_query)
        .service(on_query_last_poll_timestamp)
        .service(on_edit);
    cfg.service(scope);
}
